#include "VistaGtkmm.h"

Ventana::Ventana(xmlref_t refXml) {
    refXml->get_widget("drawingarea1", drawArea);
    
    boton_actual = PUNTO;
    recSeleccion = NULL;
    accion = NORMAL;
    tiempo_auto_guardado = 1000 * 60;               //60 segundos inicialmente
    factor_escalado = 1;
    historial_actual = 0;

    //Iniciamos el DrawingArea para que tenga un fondo blanco
    Gdk::Color color;
    color.set_rgb_p(1,1,1);
    const Gdk::Color color2 = color;
    drawArea->modify_bg(Gtk::STATE_NORMAL, color2);

    //Color por defecto para las figuras
    color_actual.set_rgb_p(0,0,0);

    // Obtenemos los widgets necesarios para su configuración
    Gtk::ImageMenuItem* pButton = NULL, *menuGuardar = NULL, *menuAbout = NULL, *auto_save_button = NULL, *open_button = NULL,
            *save_as_button = NULL, *menuNuevo = NULL;
    Gtk::Button *botonGuardarCambios = NULL;
    refXml->get_widget("imagemenuitem1", menuNuevo);
    refXml->get_widget("quit_button", pButton);
    refXml->get_widget("save_button", menuGuardar);
    refXml->get_widget("menuAbout", menuAbout);
    refXml->get_widget("auto_save_button", auto_save_button);
    refXml->get_widget("open_button", open_button);
    refXml->get_widget("save_as_button", save_as_button);
    refXml->get_widget("aboutdialog", about);
    refXml->get_widget("dialogoAutoGuardado", dialogoAutoGuardado);
    refXml->get_widget("botonGuardarCambios", botonGuardarCambios);
    refXml->get_widget("spinbuttonAutoGuardado", spinbuttonAutoGuardado);

    spinbuttonAutoGuardado->set_wrap();
    spinbuttonAutoGuardado->set_size_request(100, -1);
    Gtk::Adjustment adjust_auto_save(1.0, 1.0, 100.0, 1.0, 5.0, 0.0);
    spinbuttonAutoGuardado->set_adjustment(adjust_auto_save);

    pButton->signal_activate().connect(sigc::ptr_fun(Gtk::Main::quit));
    pButton->signal_button_release_event().connect(sigc::mem_fun(*this,&Ventana::on_salir_clicked));
    menuGuardar->signal_button_release_event().connect(sigc::mem_fun(*this, &Ventana::guardarAFichero));
    menuAbout->signal_button_release_event().connect(sigc::mem_fun(*this, &Ventana::mostrarAbout));
    botonGuardarCambios->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::guardarCambiosAutoSave));
    auto_save_button->signal_button_release_event().connect(sigc::mem_fun(*this, &Ventana::mostrarAutoSave));
    open_button->signal_button_release_event().connect(sigc::mem_fun(*this, &Ventana::cargarArchivo));
    save_as_button->signal_button_release_event().connect(sigc::mem_fun(*this, &Ventana::guardarArchivoComo));
    menuNuevo->signal_button_release_event().connect(sigc::mem_fun(*this, &Ventana::resetearPaint));

    //Widget de tipo label con la info. del boton pulsado
    refXml->get_widget("label_info", labelState);

    //Eventos para los botones
    Gtk::Button *botonPunto = NULL, *botonLinea = NULL, *botonRec = NULL, *botonTri = NULL, *botonCirc = NULL, *buttonImage = NULL;
    
    refXml->get_widget("botonPunto", botonPunto);
    refXml->get_widget("botonLinea", botonLinea);
    refXml->get_widget("botonRec", botonRec);
    refXml->get_widget("botonTri", botonTri);
    refXml->get_widget("botonCirc", botonCirc);
    refXml->get_widget("buttonImage", buttonImage);

    botonPunto->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickPunto));
    botonLinea->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickLinea));
    botonRec->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickRec));
    botonTri->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickTri));
    botonCirc->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickCirc));
    buttonImage->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickImage));

    Gtk::Button *botonSelect = NULL, *botonCopy = NULL, *botonPaste = NULL, *botonDup = NULL, *botonCut = NULL, *botonDelete = NULL,
            *botonGroup = NULL, *botonUngroup = NULL, *botonRotate = NULL, *botonColor = NULL, *buttonUndo = NULL, *buttonRedo = NULL;

    refXml->get_widget("botonSelect", botonSelect);
    refXml->get_widget("botonCopy", botonCopy);
    refXml->get_widget("botonPaste", botonPaste);
    refXml->get_widget("botonDup", botonDup);
    refXml->get_widget("botonCut", botonCut);
    refXml->get_widget("botonDelete", botonDelete);
    refXml->get_widget("botonGroup", botonGroup);
    refXml->get_widget("botonUngroup", botonUngroup);
    refXml->get_widget("botonRotate", botonRotate);
    refXml->get_widget("botonColor", botonColor);
    refXml->get_widget("buttonUndo", buttonUndo);
    refXml->get_widget("buttonRedo", buttonRedo);

    botonSelect->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickSelect));
    botonCopy->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickCopy));
    botonPaste->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickPaste));
    botonDup->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickDup));
    botonCut->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickCut));
    botonDelete->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickDelete));
    botonGroup->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickGroup));
    botonUngroup->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickUngroup));
    botonRotate->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickRotate));
    botonColor->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickPickColor));
    buttonUndo->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickUndo));
    buttonRedo->signal_clicked().connect(sigc::mem_fun(*this, &Ventana::clickRedo));

    //Eventos para el DrawArea
    drawArea->add_events(Gdk::BUTTON_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK | Gdk::KEY_PRESS_MASK | Gdk::KEY_RELEASE_MASK);
    
    drawArea->signal_button_press_event().connect(sigc::mem_fun(*this, &Ventana::button_press_event));
    drawArea->signal_button_release_event().connect(sigc::mem_fun(*this, &Ventana::button_release_event));
    drawArea->signal_motion_notify_event().connect(sigc::mem_fun(*this, &Ventana::motion_notify_event));
    drawArea->signal_expose_event().connect(sigc::mem_fun(*this, &Ventana::expose_event));
    drawArea->signal_scroll_event().connect(sigc::mem_fun(*this, &Ventana::mover_rueda));
    drawArea->signal_key_press_event().connect(sigc::mem_fun(*this, &Ventana::key_press_event));
    drawArea->get_toplevel()->signal_key_press_event().connect(sigc::mem_fun(*this, &Ventana::key_press_event));
    drawArea->get_toplevel()->signal_key_release_event().connect(sigc::mem_fun(*this, &Ventana::key_release_event));

    //Aquí colocamos el timeout que hará que cada X segundos se ejecute el autoguardado de las figuras en el fichero .txt
    sigc::connection con = Glib::signal_timeout().connect((sigc::slot<bool>)sigc::mem_fun(*this,&Ventana::on_autosave),tiempo_auto_guardado);
    conexion = con;
}

Ventana::~Ventana() {
    if(drawArea != NULL)
        delete drawArea;
    drawArea = NULL;

    if(labelState != NULL)
        delete labelState;
    labelState = NULL;

    if(recSeleccion != NULL)
        delete recSeleccion;
    recSeleccion = NULL;
}

bool Ventana::key_press_event(GdkEventKey *e) {
    if(e->keyval == GDK_Shift_L || e->keyval == GDK_Shift_R) {
        redimensionar = true;
    } else if(e->keyval == GDK_Control_L || e->keyval == GDK_Control_R) {
        rotar = true;
    }
}

bool Ventana::key_release_event(GdkEventKey *e) {
    if(e->keyval == GDK_Shift_L || e->keyval == GDK_Shift_R) {
        redimensionar = false;
    } else if(e->keyval == GDK_Control_L || e->keyval == GDK_Control_R) {
        rotar = false;
    }
}

bool Ventana::resetearPaint(GdkEventButton *e) {
    su_modelo->vaciarFiguras();
    
    Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
    drawArea->get_window()->invalidate_rect(r, false);

    return true;
}

void Ventana::cargarImagenes() {
    vector<ImagenGtkmm*> imagenes_nuevas;
    for(vector<Primitiva*>::iterator it = su_modelo->figuras.begin(); it != su_modelo->figuras.end();) {
        Imagen* pImagen = dynamic_cast<Imagen*>( *it );

        if(pImagen) {
            Cairo::RefPtr< Cairo::Context > image_context_ptr_;
            Cairo::RefPtr< Cairo::ImageSurface > image_surface_ptr_;
            Glib::RefPtr< Gdk::Pixbuf > image_ptr_;

            // Load pixbuf
            image_ptr_ = Gdk::Pixbuf::create_from_file (pImagen->GetFileName());
            // Detect transparent colors for loaded image
            Cairo::Format format = Cairo::FORMAT_RGB24;
            if (image_ptr_->get_has_alpha()) {
                format = Cairo::FORMAT_ARGB32;
            }

            // Create a new ImageSurface
            image_surface_ptr_ = Cairo::ImageSurface::create  (format, image_ptr_->get_width(), image_ptr_->get_height());
            // Create the new Context for the ImageSurface
            image_context_ptr_ = Cairo::Context::create (image_surface_ptr_);
            // Draw the image on the new Context
            Gdk::Cairo::set_source_pixbuf (image_context_ptr_, image_ptr_, 0, 0);
            image_context_ptr_->paint();

            ImagenGtkmm *pImagenGtkmm = new ImagenGtkmm(pImagen->GetX(), pImagen->GetY(), image_context_ptr_, image_surface_ptr_, image_ptr_, pImagen->GetFileName());
            imagenes_nuevas.push_back(pImagenGtkmm);
        }

        if(pImagen)
            it = su_modelo->figuras.erase(it);
        else
            it++;
    }

    for(int i = 0; i < (signed)imagenes_nuevas.size(); i++)
        su_modelo->figuras.push_back(imagenes_nuevas[i]);
}

bool Ventana::cargarArchivo(GdkEventButton *e) {
    Gtk::FileChooserDialog fcd("Selecciona un archivo para cargar las figuras", Gtk::FILE_CHOOSER_ACTION_OPEN);

    fcd.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    fcd.add_button("Aceptar", Gtk::RESPONSE_OK);

    int result = fcd.run();

    switch(result) {
        case(Gtk::RESPONSE_OK):
            su_modelo->cargarFichero(fcd.get_filename());
            cargarImagenes();
            
            Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
            drawArea->get_window()->invalidate_rect(r, false);
            break;
    }

    return true;
}

bool Ventana::guardarArchivoComo(GdkEventButton *e) {
    Gtk::FileChooserDialog fcd("Escribe el nombre del fichero a guardar", Gtk::FILE_CHOOSER_ACTION_SAVE);

    fcd.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    fcd.add_button("Aceptar", Gtk::RESPONSE_OK);

    int result = fcd.run();

    switch(result) {
        case(Gtk::RESPONSE_OK):
            su_modelo->guardarAFichero(su_modelo->figuras, fcd.get_filename());
            break;
    }

    return true;
}

bool Ventana::on_autosave() {
    su_modelo->guardarAFichero(su_modelo->figuras);

    return true;
}

void Ventana::guardarCambiosAutoSave() {
    tiempo_auto_guardado = spinbuttonAutoGuardado->get_value_as_int();
    dialogoAutoGuardado->hide();

    stringstream flujo;
    flujo << "Tiempo Auto Guardado modificado: " << tiempo_auto_guardado << " min";
    string info = flujo.str();

    labelState->set_text(info);

    sigc::connection con = Glib::signal_timeout().connect((sigc::slot<bool>)sigc::mem_fun(*this,&Ventana::on_autosave),tiempo_auto_guardado * 60);
    conexion = con;
}

bool Ventana::mostrarAutoSave(GdkEventButton *b) {
    dialogoAutoGuardado->show();
    
    return true;
}

bool Ventana::guardarAFichero(GdkEventButton *b) {
    su_modelo->guardarAFichero(su_modelo->figuras);

    return true;
}

bool Ventana::mostrarAbout(GdkEventButton *b) {
    about->show();

    return true;
}

bool Ventana::on_salir_clicked(GdkEventButton *b) {
    cout << "Salir de la aplicación\n";

    drawArea->get_toplevel()->hide();
    
    return true;
}

bool Ventana::mover_rueda(GdkEventScroll *e) {
    if(boton_actual == ROTATE || rotar) {
        int inc = -5;
        if(e->direction == GDK_SCROLL_UP) {
            inc = 5;
        }
        
        for(int i = 0; i < (signed)su_modelo->figurasSeleccionadas.size(); i++) {
            Linea* pLinea = dynamic_cast<Linea*>( su_modelo->figurasSeleccionadas[i] );
            Triangulo* pTriangulo = dynamic_cast<Triangulo*>( su_modelo->figurasSeleccionadas[i] );

            if(pLinea) {
                pLinea->Rotar(inc);
            } else if(pTriangulo) {
                pTriangulo->Rotar(inc);
            } else {
                double distOrigenYPunto = sqrt(su_modelo->figurasSeleccionadas[i]->GetX()*su_modelo->figurasSeleccionadas[i]->GetX()
                + su_modelo->figurasSeleccionadas[i]->GetY()*su_modelo->figurasSeleccionadas[i]->GetY());
                double angOrigenYPunto = atan2(su_modelo->figurasSeleccionadas[i]->GetY(), su_modelo->figurasSeleccionadas[i]->GetX()) * 180 / PI;

                double nuevoX = cos((angOrigenYPunto+inc)*PI/180)*distOrigenYPunto,
                        nuevoY = sin((angOrigenYPunto+inc)*PI/180)*distOrigenYPunto;

                su_modelo->figurasSeleccionadas[i]->SetX(nuevoX);
                su_modelo->figurasSeleccionadas[i]->SetY(nuevoY);
            }
        }

        Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
        drawArea->get_window()->invalidate_rect(r, false);

        if(boton_actual != UNDO) {
            if(historial_actual != historial.size() - 1) {
                while(historial_actual != historial.size() - 1) {
                    historial.pop_back();
                }
            }

            Historial *nuevo = new Historial(su_modelo);
            historial.push_back(nuevo);
            historial_actual = historial.size() - 1;
        }
    } else if(redimensionar) {
        if(!su_modelo->figurasSeleccionadas.empty()) {
            int inc = -5;
            if(e->direction == GDK_SCROLL_UP) {
                inc = 5;
            }

            for(int i = 0; i < (signed) su_modelo->figurasSeleccionadas.size(); i++) {
                bool aumentar = true;
                if(inc < 0)
                    aumentar = false;

                Linea* l_subclass = dynamic_cast<Linea*>(su_modelo->figurasSeleccionadas[i]);
                Rectangulo* r_subclass = dynamic_cast<Rectangulo*>(su_modelo->figurasSeleccionadas[i]);
                Triangulo* t_subclass = dynamic_cast<Triangulo*>(su_modelo->figurasSeleccionadas[i]);
                Circulo* c_subclass = dynamic_cast<Circulo*>(su_modelo->figurasSeleccionadas[i]);
                ImagenGtkmm* img_subclass = dynamic_cast<ImagenGtkmm*>(su_modelo->figurasSeleccionadas[i]);

                if(l_subclass)
                    l_subclass->Redimensionar(aumentar,true,true);
                else if(r_subclass)
                    r_subclass->Redimensionar(aumentar, true,true);
                else if(t_subclass)
                    t_subclass->Redimensionar(aumentar);
                else if(c_subclass)
                    c_subclass->Redimensionar(aumentar);
                else if(img_subclass)
                    img_subclass->Redimensionar(aumentar,true,true);
            }

            Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
            drawArea->get_window()->invalidate_rect(r, false);
        }
    } else {
        double inc = -0.1;
        if(e->direction == GDK_SCROLL_UP) {
            inc = 0.1;
        }

        factor_escalado += inc;

        Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
        drawArea->get_window()->invalidate_rect(r, false);
    }

    return true;
}

void Ventana::pintaFiguras(vector<Primitiva*> v) {
    for(int i = 0; i < (signed)v.size(); i++) {
        Punto* pPunto = dynamic_cast<Punto*>( v[i] );
        Linea* pLinea = dynamic_cast<Linea*>( v[i] );
        Rectangulo* pRectangulo = dynamic_cast<Rectangulo*>( v[i] );
        Triangulo* pTriangulo = dynamic_cast<Triangulo*>( v[i] );
        Circulo* pCirculo = dynamic_cast<Circulo*>( v[i] );
        Conjunto* pConjunto = dynamic_cast<Conjunto*>( v[i] );
        ImagenGtkmm* pImagen = dynamic_cast<ImagenGtkmm*>( v[i] );

        cout << "Figura " << i << " (" << v[i] ->GetX() << "," << v[i] ->GetY() << ")" << v[i]->GetGrados() << " RGB(" << v[i]->GetRed() << "," << v[i]->GetGreen() << "," << v[i]->GetBlue() << ")" << endl;
        
        cairo->save();
        
        cairo->set_source_rgba(v[i]->GetRed(), v[i]->GetGreen(), v[i]->GetBlue(), 1);

        if(pPunto) {
            cairo->rectangle(pPunto -> GetX(), pPunto -> GetY(), 0, 0);
            cairo->stroke();
        }
        else if(pLinea) {
            cairo->move_to(pLinea -> GetX(), pLinea -> GetY());
            cairo->line_to(pLinea -> GetQ().GetX(), pLinea -> GetQ().GetY());
            cairo->stroke();
        }
        else if(pCirculo) {
            cairo->arc(pCirculo -> GetX(), pCirculo -> GetY(), pCirculo -> GetRadio(), 0, 10 * M_PI);
            cairo->stroke();
        }
        else if(pRectangulo) {
            cairo->rectangle(pRectangulo -> GetX(), pRectangulo -> GetY(), pRectangulo -> GetAncho(), pRectangulo -> GetAlto());

            cairo->stroke();
        } else if(pTriangulo) {
            cairo->move_to(pTriangulo -> GetX(), pTriangulo -> GetY());
            cairo->line_to(pTriangulo -> GetP(1).GetX(), pTriangulo -> GetP(1).GetY());
            cairo->line_to(pTriangulo -> GetP(2).GetX(), pTriangulo -> GetP(2).GetY());
            cairo->line_to(pTriangulo -> GetX(), pTriangulo -> GetY());

            cairo->stroke();
        } else if(pConjunto) {
            pintaFiguras(pConjunto->GetComponentes());
        } else if(pImagen) {
            cairo->move_to(pImagen->GetX(), pImagen->GetY());

            // Draw the source image on the widget context
            cairo->set_source (pImagen->GetSurface(), (double)pImagen->GetX(), (double)pImagen->GetY());
            cairo->rectangle (pImagen->GetX(), pImagen->GetY(), pImagen->GetSurface()->get_width(), pImagen->GetSurface()->get_height());
            cairo->clip();
            cairo->paint();
        }

        cairo->restore();

        pPunto = NULL; pLinea = NULL; pRectangulo = NULL; pTriangulo = NULL; pCirculo = NULL; pConjunto = NULL; pImagen = NULL;
    }
}

void Ventana::pinta() {
    Gtk::Allocation allocation = drawArea->get_allocation();
    const int width = allocation.get_width();
    const int height = allocation.get_height();

    // coordinates for the center of the window
    int xc, yc;
    xc = width / 2;
    yc = height / 2;

    cairo->set_line_cap(Cairo::LINE_CAP_ROUND);
    cairo->scale(factor_escalado, factor_escalado);
    
    pintaFiguras(su_modelo->figuras);

    if(recSeleccion) {
        vector<double> dashes;
        dashes.push_back(10.0);dashes.push_back(10.0);dashes.push_back(10.0);dashes.push_back(10.0);
        cairo->set_dash (dashes, 0);
        cairo->set_source_rgba(0,0,1, 1);

        cairo->rectangle(recSeleccion -> GetX(), recSeleccion -> GetY(), recSeleccion -> GetAncho(), recSeleccion -> GetAlto());

        cairo->stroke();

        vector<double> dashes2;
        cairo->set_dash (dashes2, 0);
        cairo->set_source_rgba(0, 0, 0, 1);
    }

    cairo->save();
    cairo->stroke();
}

bool Ventana::expose_event(GdkEventExpose *e) {
    cout<< "expose_event" << endl;

    cairo = drawArea->get_window()->create_cairo_context();
    
    cairo->rectangle(e->area.x, e->area.y, e->area.width, e->area.height);
    cairo->clip();

    pinta();

    return true;
}

bool Ventana::motion_notify_event(GdkEventMotion *e) {
    cout<< "motion_notify_event" << endl;

    if(e) {
        Punto* lp = new Punto(e->x, e->y);

        if (e->state & GDK_BUTTON1_MASK) {
            switch(boton_actual) {
                case LINEA:
                    addLinea(lp,1);
                    break;
                case CIRCULO:
                    addCirc(lp,1);
                    break;
                case RECTANGULO:
                    addRec(lp,1,false);
                    break;
                case TRIANGULO:
                    addTri(lp,1);
                    break;
                case SELECT:
                    addRec(lp,1,true);
                    break;
            }
        } else if(e->state & GDK_BUTTON3_MASK && accion == MOVIMIENTO) {
            moverFigurasSeleccionadas(su_modelo ->figurasSeleccionadas, e->x - movX, e->y - movY);
            movX = e->x;
            movY = e->y;
        }
        
        if(boton_actual != PUNTO) {
            Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
            drawArea->get_window()->invalidate_rect(r, false);
        }
    }
    
    return false;
}

bool Ventana::button_press_event(GdkEventButton *e) {
    cout<< "button_press_event " << e->button << " boton_actual " << boton_actual << endl;

    if(e) {
        Punto *p = new Punto(e->x,e->y);
    
        if(boton_actual == PUNTO && e->button == 1)
            addPunto(p);
        else if(boton_actual == LINEA && e->button == 1)
            addLinea(p,0);
        else if(boton_actual == RECTANGULO && e->button == 1)
            addRec(p,0, false);
        else if(boton_actual == TRIANGULO && e->button == 1)
            addTri(p,0);
        else if(boton_actual == CIRCULO && e->button == 1)
            addCirc(p,0);
        else if(boton_actual == IMAGEN && e->button == 1)
            addImage(p);
        else if(boton_actual == SELECT) {
            if(e->button == 1) {
                addRec(p,0, true);
            } else if(e->button == 3) {
                accion = MOVIMIENTO;
                movX = e->x;
                movY = e->y;
            }
        } else if(boton_actual == COPY) {
            for(vector<Primitiva*>::iterator it = su_modelo->figurasSeleccionadas.begin(); it != su_modelo->figurasSeleccionadas.end();it++)
                su_modelo->portapapeles.push_back(*it);
        } else if(boton_actual == PASTE && su_modelo->figurasSeleccionadas.size() > 0) {
            accion = MOVIMIENTO;
            movX = e->x;
            movY = e->y;
        }
    }

    Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
    drawArea->get_window()->invalidate_rect(r, false);

    return false;
}

bool Ventana::button_release_event(GdkEventButton *e) {
    //cout<< "button_release_event " << e->button << " Accion: " << accion << endl;

    if(boton_actual == SELECT) {
        su_modelo->figurasSeleccionadas.clear();
        seleccionarFiguras();
        accion = NORMAL;
    } else if(boton_actual == PASTE) {
        //su_modelo->figurasSeleccionadas.clear();
        //accion = NORMAL;
    }

    if(boton_actual != UNDO) {
        if(historial_actual != historial.size() - 1) {
            while(historial_actual != historial.size() - 1) {
                historial.pop_back();
            }
        }

        Historial *nuevo = new Historial(su_modelo);
        historial.push_back(nuevo);
        historial_actual = historial.size() - 1;
    }

    return true;
}

void Ventana::addPunto(Punto *p) {
    p->SetColor(color_actual.get_red_p(), color_actual.get_green_p(), color_actual.get_blue_p());
    su_modelo -> figuras.push_back(p);
}

void Ventana::addLinea(Punto *p, int n) {
    Linea* l;
    
    if(n == 0) {
        l = new Linea();
        l->SetColor(color_actual.get_red_p(), color_actual.get_green_p(), color_actual.get_blue_p());
        l -> SetX(p->GetX()); l -> SetY(p->GetY());
        su_modelo -> figuras.push_back(l);
    } else if(n == 1) {
        l = (Linea*) su_modelo -> figuras.back();
        l -> SetQ(*p);
    }

    delete p;
}

void Ventana::addRec(Punto *p, int n, bool selectionRect) {
    Rectangulo* r;

    if(n == 0) {
        r = new Rectangulo();
        r->SetColor(color_actual.get_red_p(), color_actual.get_green_p(), color_actual.get_blue_p());
        if(selectionRect)
            r -> setSelectionRect();
        r -> SetX(p->GetX()); r -> SetY(p->GetY());
        
        if(selectionRect) {
            if(recSeleccion) {
                delete recSeleccion;
                recSeleccion = NULL;
            }
            recSeleccion = r;
        }
        else
            su_modelo -> figuras.push_back(r);
    } else if(n == 1) {
        if(selectionRect)
            r = recSeleccion;
        else
            r = (Rectangulo*) su_modelo -> figuras.back();

        if(r) {
            r -> SetAlto(p->GetY() - r -> GetY());
            r -> SetAncho(p->GetX() - r -> GetX());
        }
    }

    delete p;
}

void Ventana::addCirc(Punto *p, int n) {
    Circulo* c;

    if(n == 0) {
        c = new Circulo();
        c->SetColor(color_actual.get_red_p(), color_actual.get_green_p(), color_actual.get_blue_p());
        c -> SetX(p->GetX()); c -> SetY(p->GetY());
        su_modelo -> figuras.push_back(c);
    } else if(n == 1) {
        c = (Circulo*) su_modelo -> figuras.back();
        c -> SetRadio(abs(c -> GetX()-p->GetX()));
    }
    
    delete p;
}

void Ventana::addTri(Punto *p, int n) {
    Triangulo* t;
    int dX = 0;
    int maxX = 0, maxY = 0;

    if(n == 0) {
        t = new Triangulo();
        t->SetColor(color_actual.get_red_p(), color_actual.get_green_p(), color_actual.get_blue_p());
        t -> SetX(p->GetX()); t -> SetY(p->GetY());
        su_modelo -> figuras.push_back(t);
    } else if(n == 1) {
        t = (Triangulo*) su_modelo -> figuras.back();
        t -> SetP(1, p->GetX(), p->GetY());

        dX = abs(t -> GetP(1).GetX() - t -> GetX());

        maxX = max(t->GetP(1).GetX(), t -> GetX());
        maxY = max(t->GetP(1).GetY(), t -> GetY());

        t -> SetP(2, maxX-2*dX, maxY);
    }

    delete p;
}

void Ventana::seleccionarFiguras() {
    if(recSeleccion) {
        for(int i = 0; i < (signed)su_modelo -> figuras.size(); i++) {
            Punto* pPunto = dynamic_cast<Punto*>( su_modelo -> figuras[i] );
            Linea* pLinea = dynamic_cast<Linea*>( su_modelo -> figuras[i] );
            Rectangulo* pRectangulo = dynamic_cast<Rectangulo*>( su_modelo -> figuras[i] );
            Triangulo* pTriangulo = dynamic_cast<Triangulo*>( su_modelo -> figuras[i] );
            Circulo* pCirculo = dynamic_cast<Circulo*>( su_modelo -> figuras[i] );
            Conjunto* pConjunto = dynamic_cast<Conjunto*>( su_modelo -> figuras[i] );
            ImagenGtkmm* pImagen = dynamic_cast<ImagenGtkmm*>( su_modelo -> figuras[i] );
            
            if(pPunto && seleccionContienePunto(*pPunto))
                su_modelo->figurasSeleccionadas.push_back(pPunto);
            else if(pLinea && seleccionContieneLinea(pLinea))
                su_modelo->figurasSeleccionadas.push_back(pLinea);
            else if(pRectangulo && seleccionContieneRectangulo(pRectangulo))
                su_modelo->figurasSeleccionadas.push_back(pRectangulo);
            else if(pTriangulo && seleccionContieneTriangulo(pTriangulo))
                su_modelo->figurasSeleccionadas.push_back(pTriangulo);
            else if(pCirculo && seleccionContieneCirculo(pCirculo))
                su_modelo->figurasSeleccionadas.push_back(pCirculo);
            else if(pConjunto && seleccionContieneConjunto(pConjunto))
                su_modelo->figurasSeleccionadas.push_back(pConjunto);
            else if(pImagen && seleccionContieneImagen(pImagen))
                su_modelo->figurasSeleccionadas.push_back(pImagen);
        }
    }
}

bool Ventana::seleccionContienePunto(const Punto &p) {
    bool checkX, checkY;

    double distOrigenYPunto = sqrt(p.GetX()*p.GetX() + p.GetY()*p.GetY());
    double angOrigenYPunto = atan2(p.GetY(), p.GetX()) * 180 / PI;

    //cout << "Arc Tang de (" << p.GetX() << "," << p.GetY() << "): " << angOrigenYPunto << "º Ang. figura: " << p.GetGrados() << " Ant X: " << cos(angOrigenYPunto*PI/180)*distOrigenYPunto << " Ant Y: " << sin(angOrigenYPunto*PI/180)*distOrigenYPunto << " Dist. 0.0 Y Punto: " << distOrigenYPunto << " Calc X: " << cos((angOrigenYPunto+p.GetGrados())*PI/180)*distOrigenYPunto << " Calc Y: " << sin((angOrigenYPunto+p.GetGrados())*PI/180)*distOrigenYPunto << endl;

    double nuevoX = cos((angOrigenYPunto+p.GetGrados())*PI/180)*distOrigenYPunto,
            nuevoY = sin((angOrigenYPunto+p.GetGrados())*PI/180)*distOrigenYPunto;

    if(recSeleccion->GetAncho() >= 0) {
        checkX = nuevoX >= recSeleccion->GetX() && nuevoX <= recSeleccion->GetX() + recSeleccion->GetAncho();
    } else {
        checkX = !(nuevoX >= recSeleccion->GetX() && nuevoX <= recSeleccion->GetX() + recSeleccion->GetAncho());
    }

    if(recSeleccion->GetAlto() >= 0) {
        checkY = nuevoY >= recSeleccion->GetY() && nuevoY <= recSeleccion->GetY() + recSeleccion->GetAlto();
    } else {
        checkY = !(nuevoY >= recSeleccion->GetY() && nuevoY <= recSeleccion->GetY() + recSeleccion->GetAlto());
    }

    return checkX && checkY;
}

bool Ventana::seleccionContieneLinea(Linea *l) {
    Punto p(l->GetQ()), p2(l->GetX(), l->GetY());
    p.SetGrados(l->GetGrados());
    p2.SetGrados(l->GetGrados());
    
    return seleccionContienePunto(p) && seleccionContienePunto(p2);
}

bool Ventana::seleccionContieneRectangulo(Rectangulo *r) {
    Punto p(r->GetX(), r->GetY()), p2(r->GetX() + r->GetAncho(), r->GetY()),
            p3(r->GetX(), r->GetY() + r->GetAlto()),
            p4(r->GetX() + r->GetAncho(), r->GetY() + r->GetAlto());
    p.SetGrados(r->GetGrados());
    p2.SetGrados(r->GetGrados());
    p3.SetGrados(r->GetGrados());
    p4.SetGrados(r->GetGrados());
    
    return seleccionContienePunto(p) && seleccionContienePunto(p2) && seleccionContienePunto(p3) && seleccionContienePunto(p4);
}

bool Ventana::seleccionContieneTriangulo(Triangulo *t) {
    Punto p(t->GetX(), t->GetY()), p2(t->GetP(1).GetX(), t->GetP(1).GetY()),
            p3(t->GetP(2).GetX(), t->GetP(2).GetY());
    p.SetGrados(t->GetGrados());
    p2.SetGrados(t->GetGrados());
    p3.SetGrados(t->GetGrados());

    return seleccionContienePunto(p) && seleccionContienePunto(p2) && seleccionContienePunto(p3);
}

bool Ventana::seleccionContieneCirculo(Circulo *c) {
    Punto p(c->GetX() - c->GetRadio(), c->GetY() + c->GetRadio()),
            p2(c->GetX() - c->GetRadio(), c->GetY() - c->GetRadio()),
            p3(c->GetX() + c->GetRadio(), c->GetY() + c->GetRadio()),
            p4(c->GetX() + c->GetRadio(), c->GetY() - c->GetRadio());
    p.SetGrados(c->GetGrados());
    p2.SetGrados(c->GetGrados());
    p3.SetGrados(c->GetGrados());
    p4.SetGrados(c->GetGrados());
    
    return seleccionContienePunto(p) && seleccionContienePunto(p2) && seleccionContienePunto(p3) && seleccionContienePunto(p4);
}

bool Ventana::seleccionContieneConjunto(Conjunto *c) {
    bool contenido = true;
    
    if(recSeleccion) {
        for(int i = 0; i < (signed)c->GetComponentes().size(); i++) {
            Punto* pPunto = dynamic_cast<Punto*>( c->GetComponentes()[i] );
            Linea* pLinea = dynamic_cast<Linea*>( c->GetComponentes()[i] );
            Rectangulo* pRectangulo = dynamic_cast<Rectangulo*>( c->GetComponentes()[i] );
            Triangulo* pTriangulo = dynamic_cast<Triangulo*>( c->GetComponentes()[i] );
            Circulo* pCirculo = dynamic_cast<Circulo*>( c->GetComponentes()[i] );
            Conjunto* pConjunto = dynamic_cast<Conjunto*>( c->GetComponentes()[i] );

            if(pPunto && !seleccionContienePunto(*pPunto))
                contenido=false;
            else if(pLinea && !seleccionContieneLinea(pLinea))
                contenido=false;
            else if(pRectangulo && !seleccionContieneRectangulo(pRectangulo))
                contenido=false;
            else if(pTriangulo && !seleccionContieneTriangulo(pTriangulo))
                contenido=false;
            else if(pCirculo && !seleccionContieneCirculo(pCirculo))
                contenido=false;
            else if(pConjunto && !seleccionContieneConjunto(pConjunto))
                contenido=false;
        }
    }

    return contenido;
}

bool Ventana::seleccionContieneImagen(ImagenGtkmm *v) {
    Punto p(v->GetX(), v->GetY()), p2(v->GetX() + v->GetAncho(), v->GetY()),
            p3(v->GetX(), v->GetY() + v->GetAlto()),
            p4(v->GetX() + v->GetAncho(), v->GetY() + v->GetAlto());

    return seleccionContienePunto(p) && seleccionContienePunto(p2) && seleccionContienePunto(p3) && seleccionContienePunto(p4);
}

void Ventana::moverFigurasSeleccionadas(vector<Primitiva*> v, int x, int y) {
    for(int i = 0; i < (signed)v.size(); i++) {
        Punto* pPunto = dynamic_cast<Punto*>( v[i] );
        Linea* pLinea = dynamic_cast<Linea*>( v[i] );
        Rectangulo* pRectangulo = dynamic_cast<Rectangulo*>( v[i] );
        Triangulo* pTriangulo = dynamic_cast<Triangulo*>( v[i] );
        Circulo* pCirculo = dynamic_cast<Circulo*>( v[i] );
        Conjunto* pConjunto = dynamic_cast<Conjunto*>( v[i] );
        ImagenGtkmm* pImagen = dynamic_cast<ImagenGtkmm*>( v[i] );

        if(pPunto)
            pPunto->Primitiva::Move(x, y);
        else if(pLinea)
            pLinea->Move(x, y);
        else if(pRectangulo)
            pRectangulo->Primitiva::Move(x, y);
        else if(pTriangulo)
            pTriangulo->Move(x, y);
        else if(pCirculo)
            pCirculo->Primitiva::Move(x, y);
        else if(pConjunto)
            moverFigurasSeleccionadas(pConjunto->GetComponentes(), x, y);
        else if(pImagen)
            pImagen->Primitiva::Move(x, y);
    }
}

void Ventana::eliminarFigurasSeleccionadas() {
    for(vector<Primitiva*>::iterator ite = su_modelo->figuras.begin(); ite != su_modelo->figuras.end(); ) {
        if((*ite) == (*su_modelo->figurasSeleccionadas.begin())) {
            vector<Primitiva*>::iterator aux = ite;
            ite = su_modelo->figuras.erase(aux);
            su_modelo->figurasSeleccionadas.erase(su_modelo->figurasSeleccionadas.begin());
        } else {
            ite++;
        }
    }

    //Repintamos quitando las figuras que se han borrado
    Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
    drawArea->get_window()->invalidate_rect(r, false);
}

void Ventana::clickCopy() {
    boton_actual = COPY;
    for(vector<Primitiva*>::iterator it = su_modelo->figurasSeleccionadas.begin(); it != su_modelo->figurasSeleccionadas.end();it++)
        su_modelo->portapapeles.push_back(*it);
}

void Ventana::clickPaste() {
    boton_actual = PASTE;

    if(!su_modelo->portapapeles.empty()) {
        int minX = 10000,minY = 10000;
        int maxX=0,maxY=0;
        vector<Primitiva*>::iterator it;
        su_modelo->figurasSeleccionadas.clear();

        for(it = su_modelo->portapapeles.begin(); it != su_modelo->portapapeles.end();it++) {
            Punto* p_subclass = dynamic_cast<Punto*>(*it);
            Linea* l_subclass = dynamic_cast<Linea*>(*it);
            Rectangulo* r_subclass = dynamic_cast<Rectangulo*>(*it);
            Triangulo* t_subclass = dynamic_cast<Triangulo*>(*it);
            Circulo* c_subclass = dynamic_cast<Circulo*>(*it);
            Conjunto* cj_subclass = dynamic_cast<Conjunto*>(*it);
            ImagenGtkmm* img_subclass = dynamic_cast<ImagenGtkmm*>(*it);

            if(p_subclass) {
                Punto* p1 = new Punto(p_subclass->GetX()+10,p_subclass->GetY()+10);

                su_modelo->figuras.push_back(p1);

                p_subclass = (Punto*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(p_subclass);

                minX = min(p_subclass->GetX(), minX);
                minY = min(p_subclass->GetY(), minY);
                maxX = max(p_subclass->GetX(), maxX);
                maxY = max(p_subclass->GetY(), maxY);
            } else if(l_subclass) {
                Linea* l = new Linea(*l_subclass);
                l -> SetX(l->GetX()+10);
                l -> SetY(l->GetY()+10);
                Punto p(l->GetQ().GetX()+10,l->GetQ().GetY()+10);
                l -> SetQ(p);

                su_modelo->figuras.push_back(l);

                l_subclass = (Linea*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(l_subclass);

                minX = min(min(l_subclass->GetX(), l_subclass->GetQ().GetX()),minX);
                minY = min(min(l_subclass->GetQ().GetY(), l_subclass->GetY()), minY);
                maxX = max(max(l_subclass->GetQ().GetX(),l_subclass->GetX()), maxX);
                maxY = max(max(l_subclass->GetQ().GetY(),l_subclass->GetY()), maxY);
            } else if(r_subclass) {
                Rectangulo* r = new Rectangulo(*r_subclass);
                r->SetX(r->GetX()+10);
                r->SetY(r->GetY()+10);

                su_modelo->figuras.push_back(r);

                r_subclass = (Rectangulo*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(r_subclass);

                minX = min(r_subclass->GetX(), minX);
                minY = min(r_subclass->GetY(), minY);
                maxX = max(r_subclass->GetX()+(int)r_subclass->GetAncho(), maxX);
                maxY = max(r_subclass->GetY()+(int)r_subclass->GetAlto(), maxY);
            } else if(img_subclass) {
                ImagenGtkmm* r = new ImagenGtkmm(*img_subclass);
                r->SetX(r->GetX()+10);
                r->SetY(r->GetY()+10);

                su_modelo->figuras.push_back(r);

                img_subclass = (ImagenGtkmm*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(img_subclass);

                minX = min(img_subclass->GetX(), minX);
                minY = min(img_subclass->GetY(), minY);
                maxX = max(img_subclass->GetX()+(int)img_subclass->GetAncho(), maxX);
                maxY = max(img_subclass->GetY()+(int)img_subclass->GetAlto(), maxY);
            } else if(t_subclass) {

                Triangulo* t = new Triangulo(*t_subclass);
                t->SetX(t->GetX()+10);
                t->SetY(t->GetY()+10);
                t->SetP(1,t->GetP(1).GetX()+10,t->GetP(1).GetY()+10);
                t->SetP(2,t->GetP(2).GetX()+10,t->GetP(2).GetY()+10);
                su_modelo->figuras.push_back(t);

                t_subclass = (Triangulo*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(t_subclass);

                minX = min(min(min(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), minX);
                minY = min(min(min(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), minY);
                maxX = max(max(max(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), maxX);
                maxY = max(max(max(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), maxY);
            } else if(c_subclass) {
                Circulo* c = new Circulo(*c_subclass);
                c->SetCentro(c->GetX()+10,c->GetY()+10);
                su_modelo->figuras.push_back(c);

                c_subclass = (Circulo*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(c_subclass);

                minX = min(c_subclass->GetX(), minX);
                minY = min(c_subclass->GetY(), minY);
                maxX = max(c_subclass->GetX()+(int)c_subclass->GetRadio(), maxX);
                maxY = max(c_subclass->GetY()+(int)c_subclass->GetRadio(), maxY);
            } else if(cj_subclass) {
                Conjunto* cj = new Conjunto(*cj_subclass);

                cj->SetX(cj_subclass->GetX()+10);
                cj->SetY(cj_subclass->GetY()+10);
                for(int i = 0; i < (signed) cj->GetComponentes().size(); i++)
                    cj->GetComponentes()[i]->Move(10,10);

                su_modelo->figuras.push_back(cj);

                cj_subclass = (Conjunto*) su_modelo->figuras.back();
                su_modelo->figurasSeleccionadas.push_back(cj_subclass);

                minX = min(cj_subclass->GetX(),minX);
                minY = min(cj_subclass->GetY(),minY);
                maxX = max(cj_subclass->GetX()+cj_subclass->GetWidth(), maxX);
                maxY = max(cj_subclass->GetY()+cj_subclass->GetHeight(), maxY);
            }
        }

        Punto p(minX,minY);
        Rectangulo* select = new Rectangulo(p,maxX-minX,maxY-minY);
        select->setSelectionRect();
        recSeleccion = select;

        //Repintamos quitando las figuras que se han borrado
        Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
        drawArea->get_window()->invalidate_rect(r, false);

        accion = MOVIMIENTO;
    }

    su_modelo->portapapeles.clear();
}

void Ventana::clickDup() {
    boton_actual = DUP;
    clickCopy();
    clickPaste();
}

void Ventana::clickCut() {
    boton_actual = CUT;
    clickCopy();
    clickDelete();

    //Repintamos quitando las figuras que se han borrado
    Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
    drawArea->get_window()->invalidate_rect(r, false);
}

void Ventana::clickGroup() {
    boton_actual = GROUP;
    int minX = 10000, minY = 10000, maxX = 0, maxY = 0;

    for(vector<Primitiva*>::iterator it = su_modelo->figurasSeleccionadas.begin(); it != su_modelo->figurasSeleccionadas.end();it++) {
        Punto* p_subclass = dynamic_cast<Punto*>(*it);
        Linea* l_subclass = dynamic_cast<Linea*>(*it);
        Rectangulo* r_subclass = dynamic_cast<Rectangulo*>(*it);
        Triangulo* t_subclass = dynamic_cast<Triangulo*>(*it);
        Circulo* c_subclass = dynamic_cast<Circulo*>(*it);
        Conjunto* cj_subclass = dynamic_cast<Conjunto*>(*it);
        ImagenGtkmm* img_subclass = dynamic_cast<ImagenGtkmm*>(*it);

        if(p_subclass) {
            minX = min(p_subclass->GetX(), minX);
            minY = min(p_subclass->GetY(), minY);
            maxX = max(p_subclass->GetX(), maxX);
            maxY = max(p_subclass->GetY(), maxY);
        } else if(l_subclass) {
            minX = min(min(l_subclass->GetX(), l_subclass->GetQ().GetX()),minX);
            minY = min(min(l_subclass->GetQ().GetY(), l_subclass->GetY()), minY);
            maxX = max(max(l_subclass->GetQ().GetX(),l_subclass->GetX()), maxX);
            maxY = max(max(l_subclass->GetQ().GetY(),l_subclass->GetY()), maxY);
        } else if(r_subclass) {
            minX = min(r_subclass->GetX(), minX);
            minY = min(r_subclass->GetY(), minY);
            maxX = max(r_subclass->GetX()+(int)r_subclass->GetAncho(), maxX);
            maxY = max(r_subclass->GetY()+(int)r_subclass->GetAlto(), maxY);
        } else if(t_subclass) {
            minX = min(min(min(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), minX);
            minY = min(min(min(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), minY);
            maxX = max(max(max(t_subclass->GetP(2).GetX(),t_subclass->GetP(1).GetX()),t_subclass->GetX()), maxX);
            maxY = max(max(max(t_subclass->GetP(2).GetY(),t_subclass->GetP(1).GetY()),t_subclass->GetY()), maxY);
        } else if(c_subclass) {
            minX = min(c_subclass->GetX(), minX);
            minY = min(c_subclass->GetY(), minY);
            maxX = max(c_subclass->GetX()+(int)c_subclass->GetRadio(), maxX);
            maxY = max(c_subclass->GetY()+(int)c_subclass->GetRadio(), maxY);
        } else if(cj_subclass) {
            minX = min(cj_subclass->GetX(),minX);
            minY = min(cj_subclass->GetY(),minY);
            maxX = max(cj_subclass->GetX()+cj_subclass->GetWidth(), maxX);
            maxY = max(cj_subclass->GetY()+cj_subclass->GetHeight(), maxY);
        } else if(img_subclass) {
            minX = min(img_subclass->GetX(), minX);
            minY = min(img_subclass->GetY(), minY);
            maxX = max(img_subclass->GetX()+(int)img_subclass->GetAncho(), maxX);
            maxY = max(img_subclass->GetY()+(int)img_subclass->GetAlto(), maxY);
        }
    }

    Conjunto* c = new Conjunto(minX,minY,maxX-minX,maxY-minY);

    c->Agrupar(su_modelo->figurasSeleccionadas);

    su_modelo->figuras.push_back(c);

    clickDelete();
}

void Ventana::clickUngroup() {
    boton_actual = UNGROUP;

    for(int i = 0; i < (signed)su_modelo->figurasSeleccionadas.size(); i++) {
        Conjunto* cj = dynamic_cast<Conjunto*>(su_modelo->figurasSeleccionadas[i]);
        if(cj) {
            cj -> Desagrupar(su_modelo->figuras);

            for(vector<Primitiva*>::iterator it = su_modelo->figuras.begin(); it != su_modelo->figuras.end();it++) {
                if((*it) == cj) {
                    delete cj;
                    su_modelo->figuras.erase(it);
                }
            }
        }
    }
}

void Ventana::clickPickColor() {
    boton_actual = PICK_COLOR;

    Gtk::ColorSelectionDialog csd("Seleccione el color con el que se dibujarán las próximas figuras");

    int result = csd.run();

    switch(result) {
        case(Gtk::RESPONSE_OK):
            color_actual = csd.get_color_selection()->get_current_color();
            break;
    }
}

void Ventana::clickUndo() {
    boton_actual = UNDO;
    if(historial.size() > 0 && historial_actual > 0) {
        historial_actual--;

        //cout << "Num Hist. " << historial_actual << endl;

        su_modelo->figuras = historial[historial_actual]->figuras;
        su_modelo->figurasSeleccionadas = historial[historial_actual]->figurasSeleccionadas;
        su_modelo->portapapeles = historial[historial_actual]->portapapeles;

        Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
        drawArea->get_window()->invalidate_rect(r, false);
    }
}

void Ventana::clickRedo() {
    boton_actual = REDO;
    if(historial.size() > 0 && historial_actual < historial.size() - 1) {
        historial_actual++;

        //cout << "Num Hist. " << historial_actual << endl;

        su_modelo->figuras = historial[historial_actual]->figuras;
        su_modelo->figurasSeleccionadas = historial[historial_actual]->figurasSeleccionadas;
        su_modelo->portapapeles = historial[historial_actual]->portapapeles;

        Gdk::Rectangle r(0, 0, drawArea->get_allocation().get_width(), drawArea->get_allocation().get_height());
        drawArea->get_window()->invalidate_rect(r, false);
    }
}

void Ventana::addImage(Punto *p) {
    Gtk::FileChooserDialog fcd("Selecciona una imagen", Gtk::FILE_CHOOSER_ACTION_OPEN);

    fcd.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    fcd.add_button("Aceptar", Gtk::RESPONSE_OK);

    int result = fcd.run();
    switch(result) {
        case(Gtk::RESPONSE_OK):
            Cairo::RefPtr< Cairo::Context > image_context_ptr_;
            Cairo::RefPtr< Cairo::ImageSurface > image_surface_ptr_;
            Glib::RefPtr< Gdk::Pixbuf > image_ptr_;
            
            // Load pixbuf
            image_ptr_ = Gdk::Pixbuf::create_from_file (fcd.get_filename());
            // Detect transparent colors for loaded image
            Cairo::Format format = Cairo::FORMAT_RGB24;
            if (image_ptr_->get_has_alpha()) {
                format = Cairo::FORMAT_ARGB32;
            }

            // Create a new ImageSurface
            image_surface_ptr_ = Cairo::ImageSurface::create  (format, image_ptr_->get_width(), image_ptr_->get_height());
            // Create the new Context for the ImageSurface
            image_context_ptr_ = Cairo::Context::create (image_surface_ptr_);
            // Draw the image on the new Context
            Gdk::Cairo::set_source_pixbuf (image_context_ptr_, image_ptr_, 0, 0);
            image_context_ptr_->paint();

            ImagenGtkmm *img = new ImagenGtkmm(p->GetX(), p->GetY(), image_context_ptr_, image_surface_ptr_, image_ptr_, fcd.get_filename());
            su_modelo->figuras.push_back(img);

            break;
    }
}